package dexter.core.coord;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;

import dexter.core.common.FinishParams;
import dexter.core.common.FinishResult;
import dexter.net.msg.common.RequestListener;
import dexter.net.msg.common.RequestParams;
import dexter.net.msg.common.ResponseParams;
import dexter.testing.EvaluationValues;
import dexter.testing.GenericTest;
import dexter.testing.Logger;
import dexter.testing.TestFactory;
import dexter.util.ByteWrapper;


public class CoordListener implements RequestListener {

	private Coordinator coord;
	private int bport = 8000;
	private Properties props;
	
	public CoordListener(Coordinator coord) {
		this.coord = coord;
		this.props = coord.getConfig();
		coord.setStatus("STARTING LISTENER ("+props+")");
	}
	
	public ResponseParams service(RequestParams params) {
		
		String info = "CoordListener execute : "+params+" in Thread : "+Thread.currentThread().getId();
		
		ResponseParams tr = null;
		
		if (params instanceof FinishParams) {
			System.out.println(getTS()+"> FINISH START > "+info);	
			FinishParams fparams = (FinishParams) params;
			if (fparams.isRemote()) tr = finishRemoteMode(fparams);
			System.out.println(getTS()+"> FINISH END > "+info);	
	    }		
		
		
		return tr;
		
	}
	
    private ResponseParams finishRemoteMode(FinishParams params) {
		
		coord.setStatus("FINISHING REMOTE MODE ("+params+")");
		
		//Properties props = PropertiesReader.getDefaultProperties();
		
		String jobId = params.getJobId(); 
		String groupId = params.getGroupId();
		String experimentId = "xxxxxx";
		props.setProperty("session_id", jobId);
		//EvaluationValues localResult = params.getLocalResult();
		String sourceIp = params.getSourceIp();
		String classname = params.getClassName();
		byte[] classbytes = params.getClassBytes();
	
		props.setProperty("node_classname", classname);
		props.put("node_bytes", classbytes);
		
		boolean ok = true;
		
		//SAVE NODE FILE
		char spr = File.separatorChar;
		String path = "jobs"+spr+groupId+spr+jobId+spr+classname+".class";
		props.put("node_filepath", path);
		try {
		  ByteWrapper.saveClassFile(path, classbytes);
		} catch(Exception e) {
			System.out.println(getTS()+"> ERROR SAVING ("+path+")");
			ok = false;
			e.printStackTrace();
			return null;
		}
		
		//EXECUTES A NEW TEST
	
		EvaluationValues remoteResult = null;
		try {			
			remoteResult = executeRemoteTest(props);
		} catch(Exception e) {
			ok = false;
			System.out.println(getTS()+"> Test  ("+jobId+") execution error");
			e.printStackTrace();
		}
		
		if (remoteResult==null) ok=true;
		
		FinishResult result = new FinishResult(ok, experimentId, remoteResult);
		return result;
	}

	private synchronized EvaluationValues executeRemoteTest(Properties props) throws Exception {
		
		coord.setStatus("MUTEX: STARTING REMOTE TEST ("+props+")");
		//GenericTest tester = TestFactory.createTest(props, Thread.currentThread().getContextClassLoader());
		
		GenericTest tester = TestFactory.createTest(props);
		
		System.out.println(getTS()+"> CoordList : Searching Nodes...");
		
		System.out.println(getTS()+"> CoordList : Starting Test...");
		
		bport=8000+50;
		if (bport>14000) bport=8000;
		
		props.setProperty("port", ""+bport);
		
		//TEST EXECUTION
		EvaluationValues er = null;
		int count = 0;
		int TIMEOUT = 100;
		
		System.out.println("EXECUTION LAUNCHED");
		ExecutionThread executer = new ExecutionThread(tester,props);
		executer.start();
		
		while(er==null && count < TIMEOUT) {
			try { Thread.sleep(1000); } catch (Exception e) {}
			er = executer.getResult();
			count++;
			System.out.print("*");
		}
		
		if (er==null) {
			Logger log = new Logger();
			log.error("REMOTE EXCEPTION : ", new Exception("BLOCKED EXECUTION"));
			//er = new EvaluationValues(log);
		}
		
		executer.stop();

		System.out.println(getTS()+"> CoordList : Saving logs...");
		//er.getLog().log(promtp, info)
		
		System.out.println("CoordList : Returning results...");
		coord.setStatus("MUTEX: FINISHING REMOTE TEST ("+er.getLog()+")");
		return er;		
		
	}
	
	public String getTS() {
		String timestamp = "";
	    Date date = new Date();
	    SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yy hh:mm:ss");
	    timestamp = sdf.format(date);
	    return timestamp;
	}




	}
